// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/cast/sender/external_video_encoder.h"

#include <stdint.h>

#include "media/base/video_frame.h"
#include "media/base/video_types.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace media {
namespace cast {

    namespace {

        scoped_refptr<VideoFrame> CreateFrame(const uint8_t* y_plane_data,
            const gfx::Size& size)
        {
            scoped_refptr<VideoFrame> result = VideoFrame::CreateFrame(PIXEL_FORMAT_I420,
                size,
                gfx::Rect(size),
                size,
                base::TimeDelta());
            for (int y = 0, y_end = size.height(); y < y_end; ++y) {
                memcpy(result->visible_data(VideoFrame::kYPlane) + y * result->stride(VideoFrame::kYPlane),
                    y_plane_data + y * size.width(),
                    size.width());
            }
            return result;
        }

    } // namespace

    TEST(QuantizerEstimator, EstimatesForTrivialFrames)
    {
        QuantizerEstimator qe;

        const gfx::Size frame_size(320, 180);
        const std::unique_ptr<uint8_t[]> black_frame_data(
            new uint8_t[frame_size.GetArea()]);
        memset(black_frame_data.get(), 0, frame_size.GetArea());
        const scoped_refptr<VideoFrame> black_frame = CreateFrame(black_frame_data.get(), frame_size);

        // A solid color frame should always generate a minimum quantizer value (4.0)
        // as a key frame.  If it is provided repeatedly as delta frames, the minimum
        // quantizer value should be repeatedly generated since there is no difference
        // between frames.
        EXPECT_EQ(4.0, qe.EstimateForKeyFrame(*black_frame));
        for (int i = 0; i < 3; ++i)
            EXPECT_EQ(4.0, qe.EstimateForDeltaFrame(*black_frame));

        const std::unique_ptr<uint8_t[]> checkerboard_frame_data(
            new uint8_t[frame_size.GetArea()]);
        for (int i = 0, end = frame_size.GetArea(); i < end; ++i)
            checkerboard_frame_data.get()[i] = (((i % 2) == 0) ? 0 : 255);
        const scoped_refptr<VideoFrame> checkerboard_frame = CreateFrame(checkerboard_frame_data.get(), frame_size);

        // Now, introduce a frame with a checkerboard pattern.  Half of the pixels
        // will have a difference of 255, and half will have zero difference.
        // Therefore, the Shannon Entropy should be 1.0 and the resulting quantizer
        // estimate should be ~11.9.
        EXPECT_NEAR(11.9, qe.EstimateForDeltaFrame(*checkerboard_frame), 0.1);

        // Now, introduce a series of frames with "random snow" in them.  Expect this
        // results in high quantizer estimates.
        for (int i = 0; i < 3; ++i) {
            int rand_seed = 0xdeadbeef + i;
            const std::unique_ptr<uint8_t[]> random_frame_data(
                new uint8_t[frame_size.GetArea()]);
            for (int j = 0, end = frame_size.GetArea(); j < end; ++j) {
                rand_seed = (1103515245 * rand_seed + 12345) % (1 << 31);
                random_frame_data.get()[j] = static_cast<uint8_t>(rand_seed & 0xff);
            }
            const scoped_refptr<VideoFrame> random_frame = CreateFrame(random_frame_data.get(), frame_size);
            EXPECT_LE(50.0, qe.EstimateForDeltaFrame(*random_frame));
        }
    }

} // namespace cast
} // namespace media
